package com.flashphoner.api
{	
	import com.adobe.cairngorm.control.CairngormEventDispatcher;
	import com.flashphoner.Logger;
	import com.flashphoner.api.data.Call;
	import com.flashphoner.api.data.ErrorCodes;
	import com.flashphoner.api.data.ModelLocator;
	import com.flashphoner.api.data.PhoneConfig;
	import com.flashphoner.api.management.PhoneSpeaker;
	import com.flashphoner.api.management.SoundControl;
	import com.flashphoner.api.management.VideoControl;
	
	import flash.events.*;
	import flash.net.NetConnection;
	import flash.net.NetStream;
	import flash.net.Responder;
	
	import mx.controls.Alert;
	
	/**
	 * Media server outgoing communication class
	 * **/
	internal class PhoneServerProxy
	{			
		//output voice stream
		private static var outStream:NetStream;
		
		private var responder:Responder;
		private var nc:NetConnection;		
		
		public var hasDisconnectAttempt:Boolean;
		
		public static var sendVideo:Boolean = false;
		
		public var phoneSpeaker:PhoneSpeaker;
		
		private var flashAPI:Flash_API;
		public function PhoneServerProxy(responder:Responder,flashAPI:Flash_API)
		{		
			this.responder = responder;
			nc = new NetConnection();
			nc.objectEncoding = flash.net.ObjectEncoding.AMF0;
			nc.client = new PhoneCallback(flashAPI);
			phoneSpeaker = new PhoneSpeaker(nc);
			this.flashAPI = flashAPI;
		}
		
		public function sendDtmf(call:Call,dtmf:String){
			Logger.info("PhoneServerProxy.sendDtmf() "+dtmf);
			nc.call("sendDtmf",responder,dtmf,call.id);
		}
		
		public function call(visibleName:String,callee:String,isVideoCall:Boolean):void{
			Logger.info("PhoneServerProxy.call()");
			nc.call("call",responder,visibleName,callee,isVideoCall);
		}	
		
		public function hangup(call:Call):void{
			Logger.info("PhoneServerProxy.hangup() call.id: "+call.id);
			nc.call("hangup",null,call.id);
		}
		
		public function answer(call:Call,isVideoCall:Boolean):void{
			Logger.info("PhoneServerProxy.answer() call.id: "+call.id);
			nc.call("answer",null,call.id,isVideoCall);	
		}
		
		public function publish(call:Call):void{
			Logger.info("PhoneServerProxy.publish() call.id: "+call.id);			
			if (outStream==null){
				outStream = new NetStream(nc);
				outStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR,asyncErrorHandler);
				outStream.addEventListener(NetStatusEvent.NET_STATUS,onNetStatus);									
				outStream.attachAudio(SoundControl.getInstance().getMicrophone());	
				if (PhoneConfig.VIDEO_ENABLED && sendVideo){
					outStream.attachCamera(VideoControl.getInstance().getCam());	
				}		
				outStream.publish(flashAPI.modelLocator.login+"_"+call.id);
			}					
		}
		
		public function isSendVideo(flag:Boolean):void{
			sendVideo = flag;
			if (outStream == null){
				return;
			}
			if (sendVideo && flashAPI.currentCall != null && !flashAPI.currentCall.isVideoCall){
				nc.call("updateCallToVideo",null,flashAPI.currentCall.id);
			}
			if (PhoneConfig.VIDEO_ENABLED && sendVideo){
				outStream.attachCamera(VideoControl.getInstance().getCam());
			}
			if (!sendVideo){
				outStream.attachCamera(null);
			}		
		} 
		
		private function asyncErrorHandler(event: AsyncErrorEvent):void {
	    }
	    
	    private function onNetStatus(event : NetStatusEvent) : void{
		}
		
		public function unpublish(call:Call):void{			
			if (outStream!=null){				
				outStream.removeEventListener(AsyncErrorEvent.ASYNC_ERROR,asyncErrorHandler);
				outStream.removeEventListener(NetStatusEvent.NET_STATUS,onNetStatus);		
				outStream.close();
				phoneSpeaker.stop();			
				outStream=null;
			}		
		}	
		
		public function login(username:String = null, password:String = null):int{			
			var modelLocator:ModelLocator = flashAPI.modelLocator;
			var obj:Object = new Object();
			obj.registerRequired = PhoneConfig.REGISTER_REQUIRED;
			if (username == null && password == null){
				obj.mode = "click2call";
				modelLocator.mode="click2call";
			}else{
				modelLocator.mode="flashphoner";
				if (username.indexOf("sip:") != 0 || username.indexOf("@") < 4){
					return 1;
				}	
				username = username.substring(4);
				obj.login = username.substring(0,username.indexOf("@"));
				obj.password = password;
				obj.mode = "flashphoner";
				obj.sipProviderAddress = username.substring(username.indexOf("@")+1,username.indexOf(":"));
				obj.sipProviderPort = username.substring(username.indexOf(":")+1);
				
			}
			obj.visibleName = modelLocator.visibleName;
			nc.addEventListener(NetStatusEvent.NET_STATUS,netStatusHandler);	
			nc.connect(PhoneConfig.SERVER_URL+"/"+PhoneConfig.APP_NAME,obj);
			return 0;			
		}
		
		public function disconnect():void {
			hasDisconnectAttempt = true;
			nc.close();
		}
		
		public function netStatusHandler(event : NetStatusEvent) : void
		{			
			var modelLocator:ModelLocator = flashAPI.modelLocator;
			if(event.info.code == "NetConnection.Connect.Success")
			{
				Logger.info("NetConnection.Connect.Success");
				flashAPI.apiNotify.notifyConnected();	
				CairngormEventDispatcher.getInstance().dispatchEvent(new MainEvent(MainEvent.CONNECTED,flashAPI));
								
			}else if(event.info.code == "NetConnection.Connect.Failed")
			{
				Logger.info("NetConnection.Connect.Failed");
				flashAPI.apiNotify.notifyError(ErrorCodes.CONNECTION_ERROR);
				hasDisconnectAttempt = false;
			}else if (event.info.code == 'NetConnection.Connect.Rejected')
			{
				Logger.info("NetConnection.Connect.Rejected");
				Alert.show("Too many users. Please try again later.");
				hasDisconnectAttempt = false;
			}else if (event.info.code == 'NetConnection.Connect.Closed')
			{				
				Logger.info("NetConnection.Connect.Closed");
				flashAPI.apiNotify.notifyCloseConnection();
				modelLocator.logged = false;
				hasDisconnectAttempt = false;
				modelLocator.login = null;
				modelLocator.pwd = null;
			}		
		}	
		

	}
}